package com.taysear.parcel;

import java.math.BigDecimal;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.persistence.EntityManager;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;

import com.taysear.parcel.domain.Station;
import com.taysear.parcel.domain.User;
import com.taysear.parcel.util.Constants;
import com.vaadin.Application;
import com.vaadin.addon.jpacontainer.JPAContainerFactory;
import com.vaadin.service.ApplicationContext;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Window.Notification;
import com.vaadin.ui.Window;

public class ParcelApplication extends Application implements
		ApplicationContext.TransactionListener {

	private static final long serialVersionUID = -1423081740399914746L;
	public static final String PERSISTENCE_UNIT = "parcels";
	private static ThreadLocal<ParcelApplication> currentApplication = new ThreadLocal<ParcelApplication>();
	private Window mainWindow;
	private User user;
	public EntityManager em;

	public Window getMainWindow() {
		return mainWindow;
	}
	

	public User getUser() {
		return user;
	}


	public void setUser(User user) {
		this.user = user;
	}
	
	public EntityManager getEm(){
		return em;
	}

	@Override
	public void init() {
		this.getContext().addTransactionListener(this);

		this.mainWindow = new Window("Parcels");

		this.setMainWindow(mainWindow);

		mainWindow.setContent(new LoginScreen(this));
		em = JPAContainerFactory.createEntityManagerForPersistenceUnit(PERSISTENCE_UNIT);
		setTheme("parceltheme");
	}

	public void login(String username, String password) {
		UsernamePasswordToken token;

		token = new UsernamePasswordToken(username, password);
		// Remember Me built-in, just do this:
		token.setRememberMe(true);

		// With most of Shiro, you'll always want to make sure you're working
		// with the currently executing user,
		// referred to as the subject
		Subject currentUser = SecurityUtils.getSubject();

		// Authenticate
		currentUser.login(token);
	}

	public void logout() {
		getMainWindow().getApplication().close();

		Subject currentUser = SecurityUtils.getSubject();

		if (currentUser.isAuthenticated()) {
			currentUser.logout();
		}
	}

	public static ParcelApplication getInstance() {
		return ParcelApplication.currentApplication.get();
	}

	@Override
	public void transactionStart(Application application, Object transactionData) {
		if (application == ParcelApplication.this) {
			ParcelApplication.currentApplication.set(this);
		}
	}

	@Override
	public void transactionEnd(Application application, Object transactionData) {
		if (application == ParcelApplication.this) {
			ParcelApplication.currentApplication.set(null);
			ParcelApplication.currentApplication.remove();
		}
	}
	
	public Date getDateWithoutTime(Date date){
    	SimpleDateFormat sdf = new SimpleDateFormat(Constants.DATE_FORMAT_STRING);  
		Date dateWithoutTime = null;
	    try {
			dateWithoutTime = sdf.parse(sdf.format(date));
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return dateWithoutTime;
    }
	
	public String formatDateWithoutTime(Date date){
    	SimpleDateFormat sdf = new SimpleDateFormat(Constants.DATE_FORMAT_STRING);  
		return sdf.format(date);
    }
	
	public String formatDate(Date date){
    	SimpleDateFormat sdf = new SimpleDateFormat(Constants.DATE_FORMAT_STRING_LONG);  
		return sdf.format(date);
    }
	
	public Double formatDouble(String value) {
		return new BigDecimal(value).setScale(2, BigDecimal.ROUND_DOWN).doubleValue();
	}
	
	public Double formatDouble(Double value) {
		return new BigDecimal(value).setScale(2, BigDecimal.ROUND_DOWN).doubleValue();
	}
	
	public void showNotification(String message){
		getMainWindow().showNotification(message, Notification.TYPE_WARNING_MESSAGE);
	}
	
	public Date getStartOfADay(Date date){
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return new Date(cal.getTimeInMillis());
	}
	
	public Date getEndOfADay(Date date){
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.HOUR_OF_DAY, 23);
		cal.set(Calendar.MINUTE, 59);
		cal.set(Calendar.SECOND, 59);
		return new Date(cal.getTimeInMillis());
	}
	
	public Date getYesterdaysDateWithoutTime(){
		Calendar yes = Calendar.getInstance();
		yes.add(Calendar.DATE, -1);
		Date yesterday = getDateWithoutTime(new Date(yes.getTimeInMillis()));
		return yesterday;
	}
	
	public Boolean isEmpty(Object value){
		return value == null ? true : value instanceof String ? "".equalsIgnoreCase(value.toString()) ? true : false : false;
	}
	
	public Boolean compareByetes(byte []digesta, byte []digestb){
		try {
            MessageDigest m;
            m = MessageDigest.getInstance("MD5");
            return m.isEqual(digesta, digestb);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
	}

	// Logout Listener is defined for the application
	public static class LogoutListener implements Button.ClickListener {
		private static final long serialVersionUID = 3119279539728808760L;
		private ParcelApplication app;

		public LogoutListener(ParcelApplication app) {
			this.app = app;
		}

		@Override
		public void buttonClick(ClickEvent event) {
			this.app.logout();
		}
	}
}
